import { Destroyable, react, reactJson, Event, track, HasOwner, createNextAnimateFrameEvent } from "xbsj-xe2/dist-node/xe2-base-utils";
import { MyProjectManager } from "../MyProjectManager";
import { getFeatureDataset, getFeatureClassTree, getGeometryList, createPolygon, getDatasetGeometryList } from '@/api';
import { FeatureChild, FeatureTransformedChild } from '@/scripts/dataTypes/interface'
import { ESGeoLineString, ESGltfModel, ESGeoPolygon } from "esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main";
import { ObjResettingWithEvent, SceneObject } from 'xbsj-xe2/dist-node/xe2-base-objects';
import { ElMessage } from "element-plus";
import { findMaxNum, calculateDistanceInMeters, getPints, computeRot, computeInterpolationPoints, getDirectionVector, getsceneObjNumfromSceneTree, getOffsetPoints } from '@/scripts/utils';
import { positionFromCartesian } from "xbsj-xe2/dist-node/xe2-base-cesium";
import * as Cesium from "cesium";
import { geoDestination } from "xbsj-xe2/dist-node/xe2-base-objects";
import { ESRtsFeatureAdding } from "../esobjs/ESRtsFeatureAdding";


class PointsChoose extends Destroyable {
    constructor(batchSet: BatchSet, owner: MyProjectManager) {
        super();
        const viewer = owner.activeViewer
        if (!viewer) return;
        if (!batchSet.geometryId) {
            ElMessage.error('请先选择几何体')
            batchSet.isHighlight = ""
            return;
        }

        this.dispose(viewer.clickEvent.don(async e => {
            
            if (!e.screenPosition) return;
            if (!e.mouseEvent || (e.mouseEvent.button == 2)) return;

            const result = await viewer.pickPosition(e.screenPosition) as any

            if (!result || this.isDestroyed()) return;

            const sceneObject = owner.createSceneObject(ESRtsFeatureAdding) as ESRtsFeatureAdding
            const url = batchSet.sourceType == 'lib' ? `${owner.cimrtsManager.cimrtsIp}/lib/gltf/${batchSet.geometryId}/0.glb` : `${owner.cimrtsManager.cimrtsIp}/ds/gltf/${batchSet.currentDataSet}/${batchSet.geometryId}/0.glb`
            sceneObject.url = url
            sceneObject.position = result
            sceneObject.rotation = [batchSet.pointH, batchSet.pointP, batchSet.pointR]
            sceneObject.datasetName = batchSet.currentDataSet
            sceneObject.featureClassId = batchSet.currentFeatureClass
            sceneObject.geometryId = batchSet.geometryId
            sceneObject.tileServiceName = owner.cimrtsManager.tileServiceName


            const treeItem = owner.createdTreeItem(owner.cimrtsSceneTreeWrapper)
            treeItem.sceneObject = sceneObject;

            const name = "批量放置_" + batchSet.currentFeatureClassName
            const num = getsceneObjNumfromSceneTree(sceneObject.typeName, owner.cimrtsSceneTreeWrapper);
            treeItem.name = `${name}(${num})`


        }))
    }
}
class LinesChoose extends Destroyable {
    constructor(batchSet: BatchSet, owner: MyProjectManager) {
        super();
        const viewer = owner.activeViewer
        if (!viewer) return;
        if (!batchSet.geometryId) {
            ElMessage.error('请先选择几何体')
            batchSet.isHighlight = ""
            return;
        }

        // 创建线
        const sceneObject = owner.createSceneObject(ESGeoLineString) as ESGeoLineString
        sceneObject.editing = true

        {
            const updata = async () => {
                if (batchSet.isHighlight != 'line') return;
                if (sceneObject.editing) return;
                if (!sceneObject.points || sceneObject.points.length < 2) return;
                batchSet.lineEnable = true
            }
            sceneObject.dispose(sceneObject.editingChanged.don(updata))
        }

        {
            const updata = async () => {
                if (!sceneObject.points) return;

                const { computePois, computeRots } = batchSet.getPointAndAngle(sceneObject.points)

                if (computePois.length >= 100) {
                    batchSet.lineLengthGreaterEnable = true
                    batchSet.lineLengthNum = computePois.length
                } else {
                    // 创建模型
                    batchSet.createFeatureByLine(computePois, computeRots)
                    batchSet.isHighlight = ""
                }
            }
            this.dispose(batchSet.lineEnableEvent.don(updata))
        }

        {
            const updata = async () => {
                if (!sceneObject.points) return;

                const { computePois, computeRots } = batchSet.getPointAndAngle(sceneObject.points)


                // 创建模型
                batchSet.createFeatureByLine(computePois, computeRots)
                batchSet.isHighlight = ""
            }
            this.dispose(batchSet.lineLengthGreaterEnableEvent.don(updata))
        }

        this.dispose(() => {
            batchSet.lineLengthGreaterEnable = false
            batchSet.lineLengthNum = 0
            batchSet.lineEnable = false
            sceneObject.editing = false
            owner.destroySceneObject(sceneObject)
        })


    }
}
class PlaneChoose extends Destroyable {
    constructor(batchSet: BatchSet, owner: MyProjectManager) {
        super();
        const viewer = owner.activeViewer
        if (!viewer) return;
        if (!batchSet.geometryId) {
            ElMessage.error('请先选择几何体')
            batchSet.isHighlight = ""
            return;
        }

        const sceneObject = owner.createSceneObject(ESGeoPolygon) as ESGeoPolygon
        sceneObject.stroked = true
        sceneObject.filled = false
        sceneObject.strokeWidth = 2
        sceneObject.editing = true

        {
            const updata = async () => {
                if (batchSet.isHighlight != 'plane') return;
                if (sceneObject.editing) return;
                if (!sceneObject.points || sceneObject.points.length < 3) return;
                batchSet.planeEnable = true

            }
            sceneObject.dispose(sceneObject.editingChanged.don(updata))
        }
        {
            const updata = async () => {
                if (!sceneObject.points) return;

                const ps = [...sceneObject.points, sceneObject.points[0]]
                const points = await batchSet.getPoiPort(batchSet.xGap, batchSet.yGap, ps)
                if (points.length >= 100) {
                    batchSet.planeLengthGreaterEnable = true
                    batchSet.planeLengthNum = points.length

                } else {
                    batchSet.createFeatureByPolygon(points)
                    batchSet.isHighlight = ""
                }

            }
            this.dispose(batchSet.planeEnableEvent.don(updata))
        }

        {
            const updata = async () => {
                if (!sceneObject.points) return;
                const ps = [...sceneObject.points, sceneObject.points[0]]
                const points = await batchSet.getPoiPort(batchSet.xGap, batchSet.yGap, ps)
                batchSet.createFeatureByPolygon(points)

                batchSet.isHighlight = ""

            }
            this.dispose(batchSet.planeLengthGreaterEnableEvent.don(updata))
        }

        this.dispose(() => {
            batchSet.planeLengthGreaterEnable = false
            batchSet.planeLengthNum = 0
            batchSet.planeEnable = false
            sceneObject.editing = false
            owner.destroySceneObject(sceneObject)
        })
    }
}

export class BatchSet extends HasOwner<MyProjectManager> {

    // 数据集列表
    private _dataSet = this.dv(reactJson<any>([]));
    get dataSet() { return this._dataSet.value }
    get dataSetChanged() { return this._dataSet.changed }

    // 被选中的数据集
    private _currentDataSet = this.dv(react<string>(""));
    get currentDataSet() { return this._currentDataSet.value; }
    set currentDataSet(value) { this._currentDataSet.value = value }
    get currentDataSetChanged() { return this._currentDataSet.changed; }

    // 几何库列表
    private _geometryLib = this.dv(reactJson<any>([]));
    get geometryLib() { return this._geometryLib.value }
    set geometryLib(value) { this._geometryLib.value = value }
    get geometryLibChanged() { return this._geometryLib.changed }

    private _currentGeometry = this.dv(react<string>(""));
    get currentGeometry() { return this._currentGeometry.value; }
    set currentGeometry(value) { this._currentGeometry.value = value }
    get currentGeometryChanged() { return this._currentGeometry.changed; }

    // 数据源类型
    private _sourceType = this.dv(react<string>(""));
    get sourceType() { return this._sourceType.value; }
    set sourceType(value) { this._sourceType.value = value }
    get sourceTypeChanged() { return this._sourceType.changed; }

    // 被选中的几何体id
    private _geometryId = this.dv(react<string>(""));
    get geometryId() { return this._geometryId.value; }
    set geometryId(value) { this._geometryId.value = value }
    get geometryIdChanged() { return this._geometryId.changed; }

    // 几何体长
    private _geometryLength = this.dv(react(0));
    get geometryLength() { return this._geometryLength.value; }
    set geometryLength(value) { this._geometryLength.value = value }
    get geometryLengthChanged() { return this._geometryLength.changed; }

    // 几何体宽
    private _geometryWeight = this.dv(react(0));
    get geometryWeight() { return this._geometryWeight.value; }
    set geometryWeight(value) { this._geometryWeight.value = value }
    get geometryWeightChanged() { return this._geometryWeight.changed; }

    // 几何体高
    private _geometryHeight = this.dv(react(0));
    get geometryHeight() { return this._geometryHeight.value; }
    set geometryHeight(value) { this._geometryHeight.value = value }
    get geometryHeightChanged() { return this._geometryHeight.changed; }

    // 要素类树
    private _featureClassTree = this.dv(reactJson<any>([]));
    get featureClassTree() { return this._featureClassTree.value }
    set featureClassTree(value) { this._featureClassTree.value = value }
    get featureClassTreeChanged() { return this._featureClassTree.changed }

    // 被选中的要素类id
    private _currentFeatureClass = this.dv(react<string>(""));
    get currentFeatureClass() { return this._currentFeatureClass.value; }
    set currentFeatureClass(value) { this._currentFeatureClass.value = value }
    get currentFeatureClassChanged() { return this._currentFeatureClass.changed; }

    // 被选中的要素类名称
    private _currentFeatureClassName = this.dv(react<string>(""));
    get currentFeatureClassName() { return this._currentFeatureClassName.value; }
    set currentFeatureClassName(value) { this._currentFeatureClassName.value = value }
    get currentFeatureClassNameChanged() { return this._currentFeatureClassName.changed; }

    // 标记点击
    private _isHighlight = this.dv(react<string>(""));
    get isHighlight() { return this._isHighlight.value; }
    set isHighlight(value) { this._isHighlight.value = value }
    get isHighlightChanged() { return this._isHighlight.changed; }

    /**
     *  拾取点处理
     * createNextAnimateFrameEvent再次触发settingwithEvent
     */
    private _event = this.dv(createNextAnimateFrameEvent(this.isHighlightChanged));
    private _pickSetting = this.dv(new ObjResettingWithEvent(this._event, () => {

        if (!this.isHighlight) {
            return undefined
        }
        switch (this.isHighlight) {
            case 'point':
                return new PointsChoose(this, this.owner);
            case 'line':
                return new LinesChoose(this, this.owner);
            case 'plane':
                return new PlaneChoose(this, this.owner);
            default: return undefined
        }

    }))
    get pickSetting() { return this._pickSetting; }

    // point 模式的 hpr
    private _pointH = this.dv(react(90));
    get pointH() { return this._pointH.value; }
    set pointH(value) { this._pointH.value = value }
    get pointHChanged() { return this._pointH.changed; }

    private _pointP = this.dv(react(0));
    get pointP() { return this._pointP.value; }
    set pointP(value) { this._pointP.value = value }
    get pointPChanged() { return this._pointP.changed; }

    private _pointR = this.dv(react(0));
    get pointR() { return this._pointR.value; }
    set pointR(value) { this._pointR.value = value }
    get pointRChanged() { return this._pointR.changed; }

    // plane 模式的 hpr x间距 y间距
    private _planeH = this.dv(react(0));
    get planeH() { return this._planeH.value; }
    set planeH(value) { this._planeH.value = value }
    get planeHChanged() { return this._planeH.changed; }

    private _planeP = this.dv(react(0));
    get planeP() { return this._planeP.value; }
    set planeP(value) { this._planeP.value = value }
    get planePChanged() { return this._planeP.changed; }

    private _planeR = this.dv(react(0));
    get planeR() { return this._planeR.value; }
    set planeR(value) { this._planeR.value = value }
    get planeRChanged() { return this._planeR.changed; }

    private _xGap = this.dv(react(10));
    get xGap() { return this._xGap.value; }
    set xGap(value) { this._xGap.value = value }
    get xGapChanged() { return this._xGap.changed; }

    private _yGap = this.dv(react(10));
    get yGap() { return this._yGap.value; }
    set yGap(value) { this._yGap.value = value }
    get yGapChanged() { return this._yGap.changed; }

    // 多边形编辑结束开启
    private _planeEnable = this.dv(react(false));
    get planeEnable() { return this._planeEnable.value; }
    set planeEnable(value) { this._planeEnable.value = value }
    get planeEnableChanged() { return this._planeEnable.changed; }

    // 设置面参数点击确定事件
    private _planeEnableEvent = this.dv(new Event());
    get planeEnableEvent() { return this._planeEnableEvent; }

    // 设置面 点位过多时开启
    private _planeLengthGreaterEnable = this.dv(react(false));
    get planeLengthGreaterEnable() { return this._planeLengthGreaterEnable.value; }
    set planeLengthGreaterEnable(value) { this._planeLengthGreaterEnable.value = value }
    get planeLengthGreaterEnableChanged() { return this._planeLengthGreaterEnable.changed; }

    // 设置面 点位过多时 点击确定事件
    private _planeLengthGreaterEnableEvent = this.dv(new Event());
    get planeLengthGreaterEnableEvent() { return this._planeLengthGreaterEnableEvent; }

    // 设置面 点位个数
    private _planeLengthNum = this.dv(react(0));
    get planeLengthNum() { return this._planeLengthNum.value; }
    set planeLengthNum(value) { this._planeLengthNum.value = value }
    get planeLengthNumChanged() { return this._planeLengthNum.changed; }

    // line 模式的 hpr 间距 
    private _lineH = this.dv(react(0));
    get lineH() { return this._lineH.value; }
    set lineH(value) { this._lineH.value = value }
    get lineHChanged() { return this._lineH.changed; }

    private _lineP = this.dv(react(0));
    get lineP() { return this._lineP.value; }
    set lineP(value) { this._lineP.value = value }
    get linePChanged() { return this._lineP.changed; }

    private _lineR = this.dv(react(0));
    get lineR() { return this._lineR.value; }
    set lineR(value) { this._lineR.value = value }
    get lineRChanged() { return this._lineR.changed; }

    private _lineGap = this.dv(react(10));
    get lineGap() { return this._lineGap.value; }
    set lineGap(value) { this._lineGap.value = value }
    get lineGapChanged() { return this._lineGap.changed; }

    // 偏移
    private _offset = this.dv(react(10));
    get offset() { return this._offset.value; }
    set offset(value) { this._offset.value = value }
    get offsetChanged() { return this._offset.changed; }

    // 线放置文件夹个数
    private _lineGroupNum = this.dv(react(1));
    get lineGroupNum() { return this._lineGroupNum.value; }
    set lineGroupNum(value) { this._lineGroupNum.value = value }
    get lineGroupNumChanged() { return this._lineGroupNum.changed; }

    // 折线编辑结束开启
    private _lineEnable = this.dv(react(false));
    get lineEnable() { return this._lineEnable.value; }
    set lineEnable(value) { this._lineEnable.value = value }
    get lineEnableChanged() { return this._lineEnable.changed; }

    // 设置面参数点击确定事件
    private _lineEnableEvent = this.dv(new Event());
    get lineEnableEvent() { return this._lineEnableEvent; }

    // 设置线 点位过多时开启
    private _lineLengthGreaterEnable = this.dv(react(false));
    get lineLengthGreaterEnable() { return this._lineLengthGreaterEnable.value; }
    set lineLengthGreaterEnable(value) { this._lineLengthGreaterEnable.value = value }
    get lineLengthGreaterEnableChanged() { return this._lineLengthGreaterEnable.changed; }

    // 设置线 点位个数
    private _lineLengthNum = this.dv(react(0));
    get lineLengthNum() { return this._lineLengthNum.value; }
    set lineLengthNum(value) { this._lineLengthNum.value = value }
    get lineLengthNumChanged() { return this._lineLengthNum.changed; }

    // 设置线 点位过多时 点击确定事件
    private _lineLengthGreaterEnableEvent = this.dv(new Event());
    get lineLengthGreaterEnableEvent() { return this._lineLengthGreaterEnableEvent; }

    // 获取数据集列表
    async getDatasetList() {
        const res = await getFeatureDataset(this._tileServiceName)
        // @ts-ignore
        if (res.status !== 'ok') return
        this._dataSet.value = res.data
    }
    // 获取几何列表
    async geometryLibList(param: any = {}) {
        const res = await getGeometryList(param)
        // @ts-ignore
        if (res.status !== 'ok') return
        this._geometryLib.value = res.data.data
    }
    // 根据id获取几何列表
    async getGeometryListById(param: any = {}) {
        const res = await getGeometryList(param)
        // @ts-ignore
        if (res.status !== 'ok') return []
        return res.data.data[0]
    }
    // 获取要素列表
    async getFeatureList(param: any) {
        const res = await getDatasetGeometryList(param)
        // @ts-ignore
        if (res.status !== 'ok') return
        return {
            total: res.data.total,
            tableData: res.data.data
        }
    }
    /**递归children，过滤字段*/
    transformChildren(children: FeatureChild[]): FeatureTransformedChild[] {
        if (Array.isArray(children)) {
            return children.map(child => ({
                label: child.className,
                value: child.id,
                children: child.children ? this.transformChildren(child.children) : []
            }));
        }
        return [];
    }
    // 获取要素类树
    async getTreeList() {
        const res = await getFeatureClassTree(this.currentDataSet)
        // @ts-ignore
        if (res.status !== 'ok') return
        this.featureClassTree = this.transformChildren(res.data)
    }


    // 面拆分
    async getPoiPort(xGap: any, yGap: any, points: any) {
        const params = {
            tileServiceName: this._tileServiceName,
            polygon: points,
            xjiange: xGap,
            yjiange: yGap,
        }
        const res = await createPolygon(params)
        // @ts-ignore
        if (res.status !== 'ok') return []
        return res.data

    }

    // 计算插值点和角度
    getPointAndAngle(pois: any) {
        const p = [...pois]
        const l = pois.length
        // 收集差值点
        let computePois: any[] = []
        // 收集差值点角度
        let computeRots: any[] = []

        computePois = getPints(p, this.lineGap)

        for (let i = 0; i < computePois.length - 1; i++) {
            // 计算角度值
            computeRots.push(computeRot(computePois[i], computePois[i + 1]))
        }
        computeRots.push(computeRots[computeRots.length - 1])
        return {
            computePois,
            computeRots
        }
    }

    // 根据折线创建要素
    async createFeatureByLine(pois: any, rots: any) {

        // 1.创建一个文件夹
        const group = this.owner.cimrtsSceneTreeWrapper?.createGroupTreeItem() as any
        const json = this.owner.cimrtsSceneTreeWrapper?.json.root.children as any
        const name = "批量放置_线_" + this.currentFeatureClassName
        const num = this.owner.setGroupName(json, name)
        group.name = `${name}(${num})`

        if (pois.length > 100) pois = pois.slice(0, 100)

        pois.map(async (e: any, i: any) => {

            let sceneObject = this.owner.createSceneObject(ESRtsFeatureAdding) as ESRtsFeatureAdding
            const url = this.sourceType == 'lib' ? `${this.owner.cimrtsManager.cimrtsIp}/lib/gltf/${this.geometryId}/0.glb` : `${this.owner.cimrtsManager.cimrtsIp}/ds/gltf/${this.currentDataSet}/${this.geometryId}/0.glb`
            sceneObject.url = url
            sceneObject.rotation = [this.lineH + rots[i][0], this.lineP + rots[i][1], this.lineR + rots[i][2]]
            sceneObject.position = getOffsetPoints(pois[i], [...sceneObject.rotation], this.offset)
            sceneObject.datasetName = this.currentDataSet
            sceneObject.featureClassId = this.currentFeatureClass
            sceneObject.geometryId = this.geometryId
            sceneObject.tileServiceName = this.owner.cimrtsManager.tileServiceName


            const treeItem = this.owner.createdTreeItemInnerGroup(this.owner.cimrtsSceneTreeWrapper, group)
            treeItem.sceneObject = sceneObject;

            const name = "批量放置_" + this.currentFeatureClassName
            const num = getsceneObjNumfromSceneTree(sceneObject.typeName, this.owner.cimrtsSceneTreeWrapper);
            treeItem.name = `${name}(${num})`
        })
    }

    // 根据多边形创建要素
    async createFeatureByPolygon(points: any) {
        // 1.创建一个文件夹
        const group = this.owner.cimrtsSceneTreeWrapper?.createGroupTreeItem() as any
        const json = this.owner.cimrtsSceneTreeWrapper?.json.root.children as any
        const name = "批量放置_面_" + this.currentFeatureClassName
        const num = this.owner.setGroupName(json, name)
        group.name = `${name}(${num})`

        if (points.length > 100) points = points.slice(0, 100)

        points.map(async (e: any, i: any) => {

            const height = await this.owner.activeViewer?.getHeightByLonLat(e[0], e[1])
            e.push(height)

            let sceneObject = this.owner.createSceneObject(ESRtsFeatureAdding) as ESRtsFeatureAdding
            const url = this.sourceType == 'lib' ? `${this.owner.cimrtsManager.cimrtsIp}/lib/gltf/${this.geometryId}/0.glb` : `${this.owner.cimrtsManager.cimrtsIp}/ds/gltf/${this.currentDataSet}/${this.geometryId}/0.glb`
            sceneObject.url = url
            // @ts-ignore
            sceneObject.position = points[i]
            sceneObject.rotation = [this.planeH, this.planeP, this.planeR]
            sceneObject.datasetName = this.currentDataSet
            sceneObject.featureClassId = this.currentFeatureClass
            sceneObject.geometryId = this.geometryId
            sceneObject.tileServiceName = this.owner.cimrtsManager.tileServiceName


            const treeItem = this.owner.createdTreeItemInnerGroup(this.owner.cimrtsSceneTreeWrapper, group)
            treeItem.sceneObject = sceneObject;
            const name = "批量放置_" + this.currentFeatureClassName
            const num = getsceneObjNumfromSceneTree(sceneObject.typeName, this.owner.cimrtsSceneTreeWrapper);
            treeItem.name = `${name}(${num})`
        })
    }

    // 初始化
    async init() {
        // 获取数据集列表
        await this.getDatasetList()

    }

    clear() {
        this.isHighlight = ""
    }


    constructor(public _tileServiceName: string, owner: MyProjectManager) {
        super(owner);
        {
            // 监听数据集变化 根据数据集获取要素类树 
            const updata = (val: string) => {
                this.getTreeList()
            }
            this.dispose(this.currentDataSetChanged.don(updata))
        }
        {
            // 几何体id变化了设置 长宽高
            const updata = async (val: string) => {
                if (!this.geometryId) {
                    this.geometryLength = 0
                    this.geometryWeight = 0
                    this.geometryHeight = 0
                    return;
                }
                let data: any = {}
                if (this.sourceType == 'lib') {
                    const param = {
                        "geometryId": this.geometryId
                    }
                    data = await this.getGeometryListById(param)
                } else if (this.sourceType == 'dataset') {
                    const param = {
                        "datasetName": this.currentDataSet,
                        "geometryId": this.geometryId
                    }
                    const res = await this.getFeatureList(param) as any
                    data = res.tableData[0]
                }
                this.geometryLength = Number((data.maxx - data.minx).toFixed(3))
                this.geometryWeight = Number((data.maxy - data.miny).toFixed(3))
                this.geometryHeight = Number((data.maxz - data.minz).toFixed(3))
                this.offset = -data.minx

            }
            this.dispose(this.geometryIdChanged.don(updata))
        }
    }
}















